/* verilator lint_off UNUSEDSIGNAL */
`include "DEFWIDTH.v"

module MEM_STAGE(
    input clk,
    input reset,
    //allowin
    output mem_allowin,
    input wb_allowin,
    //from exe
    input exe_to_mem_valid,
    input [`EXE_TO_MEM_BUS_WD -1:0] exe_to_mem_bus,
	//to exe
	output [`MEM_TO_EXE_BRBUS_WD -1:0] mem_to_exe_brbus,

    //to wb
    output mem_to_wb_valid,
    output [`MEM_TO_WB_BUS_WD -1:0] mem_to_wb_bus,
	//from wb
	input [`WB_TO_MEM_BRBUS_WD -1:0] wb_to_mem_brbus,

    //inst_load
    input [31:0] data_sram_rdata,

    //bypass
    output [`MEM_TO_ID_BYPASS_WD -1:0] mem_to_id_bypass,
    output [4:0] mem_to_id_rdbypass,
    output       mem_to_id_rfwenbypass,
	output [`MEM_TO_ID_CFBYPASS_WD -1:0] mem_to_id_cfbypass,
    output [11:0] mem_to_id_csrbypass,
    output       mem_to_id_cfwenbypass,


	output		 mem_to_exe_brjmpbypass,
	input        wb_to_mem_brjmpbypass


);
reg mem_valid;
wire mem_ready_go,mem_flush;

reg [`EXE_TO_MEM_BUS_WD -1:0] exe_to_mem_bus_r;

wire        dst_load,dst_writeback,dst_writeback_csr;
wire [ 3:0] ls_op;
wire [ 4:0] rd;
wire [31:0] rs1;
wire [11:0] csr;
wire [31:0] alu_result,writeback_result;
wire [31:0] mem_pc,mem_dnpc,mem_inst,mem_tvec;
wire        mem_ebreak,mem_ecall;

//MEM1,输入
assign mem_ready_go = 1'b1;
assign mem_flush = wb_to_mem_brjmpbypass;
assign mem_allowin = !mem_valid || (mem_ready_go && wb_allowin);
always @(posedge clk) begin
    if(reset) begin
        mem_valid <= 1'b0;
    end else if(mem_allowin) begin
        mem_valid <= exe_to_mem_valid;
    end 

    if(mem_allowin && exe_to_mem_valid) begin
        exe_to_mem_bus_r <= exe_to_mem_bus;
    end else begin
		exe_to_mem_bus_r <= 'b0;
	end 
end

assign {
	dst_load,
	dst_writeback,
	dst_writeback_csr,
	mem_inst,
    ls_op,
    alu_result,
	csr,
	rs1,
    rd,
    mem_pc,
	mem_dnpc,
    mem_ebreak,
	mem_ecall,
	mem_tvec
} = mem_flush ? 'b0 : exe_to_mem_bus_r[`EXE_TO_MEM_BUS_WD -1:0];


//MEM2,区分load指令写回与直接写回(均属于writeback方式)
//load:将MEM[ RF[rs1]+imm ]读到RF[rd]中
//     MEM[ RF[rs1]+imm ] = data_sram_rdata
//direct:将alu_result直接写回到RF[rd]中
wire [31:0] load_result;
assign load_result = ls_op[2] ? data_sram_rdata[31:0]										 :
					 ls_op[1] ? {{16{data_sram_rdata[15] & ls_op[3]}},data_sram_rdata[15:0]} :
					 ls_op[0] ? {{24{data_sram_rdata[ 7] & ls_op[3]}},data_sram_rdata[ 7:0]} : 32'b0;

assign writeback_result = dst_load ? load_result : alu_result;

//MEM3,输出
assign mem_to_wb_valid = mem_valid && mem_ready_go;
assign mem_to_wb_bus = {
    dst_writeback, //1
	dst_writeback_csr,
	mem_inst, //32
	csr, //12
	rs1,
    rd, //5
    writeback_result, //32
    mem_pc, //32
	mem_dnpc, //32
    mem_ebreak, //1
	mem_ecall,
	mem_tvec
};
assign mem_to_id_bypass = writeback_result;
assign mem_to_id_rdbypass = rd;
assign mem_to_id_rfwenbypass = dst_writeback;
assign mem_to_id_cfbypass = rs1;
assign mem_to_id_csrbypass = csr;
assign mem_to_id_cfwenbypass = dst_writeback_csr;


assign mem_to_exe_brjmpbypass = wb_to_mem_brjmpbypass;
assign mem_to_exe_brbus =  wb_to_mem_brbus;

endmodule
